{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "52545e6a",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "import numpy as np\n",
    "from sklearn.preprocessing import MinMaxScaler\n",
    "import matplotlib.pyplot as plt\n",
    "from core.model import Model\n",
    "\n",
    "import json"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "2797ad65",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_results(predicted_data, true_data):\n",
    "    fig = plt.figure(facecolor='white')\n",
    "    ax = fig.add_subplot(111)\n",
    "    ax.plot(true_data, label='True Data')\n",
    "    plt.plot(predicted_data, label='Prediction')\n",
    "    plt.legend()\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c4b0840c",
   "metadata": {},
   "outputs": [],
   "source": [
    "df = pd.read_csv('./data/sh600031.csv')  # 读取股票文件\n",
    "df.set_index('date', inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "439b183e",
   "metadata": {},
   "outputs": [],
   "source": [
    "df.drop(['volume'],axis=1,inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "588096bf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>open</th>\n",
       "      <th>high</th>\n",
       "      <th>low</th>\n",
       "      <th>close</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2003-07-03</th>\n",
       "      <td>23.00</td>\n",
       "      <td>23.00</td>\n",
       "      <td>20.10</td>\n",
       "      <td>21.30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2003-07-04</th>\n",
       "      <td>21.30</td>\n",
       "      <td>22.18</td>\n",
       "      <td>21.05</td>\n",
       "      <td>21.84</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2003-07-07</th>\n",
       "      <td>21.90</td>\n",
       "      <td>21.96</td>\n",
       "      <td>21.51</td>\n",
       "      <td>21.80</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2003-07-08</th>\n",
       "      <td>21.80</td>\n",
       "      <td>22.22</td>\n",
       "      <td>21.70</td>\n",
       "      <td>21.91</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2003-07-09</th>\n",
       "      <td>21.75</td>\n",
       "      <td>22.65</td>\n",
       "      <td>21.70</td>\n",
       "      <td>22.47</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "             open   high    low  close\n",
       "date                                  \n",
       "2003-07-03  23.00  23.00  20.10  21.30\n",
       "2003-07-04  21.30  22.18  21.05  21.84\n",
       "2003-07-07  21.90  21.96  21.51  21.80\n",
       "2003-07-08  21.80  22.22  21.70  21.91\n",
       "2003-07-09  21.75  22.65  21.70  22.47"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "8e91a869",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.27901685 0.27674383 0.25182185 0.26343232]\n",
      " [0.2532241  0.2643365  0.26720643 0.27196583]\n",
      " [0.26232743 0.2610077  0.27465585 0.27133372]\n",
      " ...\n",
      " [0.27901685 0.27674383 0.28987852 0.28334382]\n",
      " [0.27218935 0.27507943 0.28599185 0.28603032]\n",
      " [0.27279624 0.275836   0.28971657 0.28223765]]\n"
     ]
    }
   ],
   "source": [
    "# 获取DataFrame中的数据，形式为数组array形式\n",
    "values = df.values\n",
    "# 确保所有数据为float类型\n",
    "values = values.astype('float32')\n",
    "\n",
    "# 特征的归一化处理\n",
    "scaler = MinMaxScaler(feature_range=(0, 1))\n",
    "scaled = scaler.fit_transform(values)\n",
    "\n",
    "print(scaled)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "fbdb18bb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义series_to_supervised()函数\n",
    "# 将时间序列转换为监督学习问题\n",
    "def series_to_supervised(data, n_in=1, n_out=1, dropnan=True):\n",
    "    \"\"\"\n",
    "    将时间序列框定为有监督的学习数据集。\n",
    "        论据：\n",
    "        数据：作为列表或NumPy数组的观察序列。\n",
    "        n_in：作为输入的滞后观测数（X）。\n",
    "        n_out：作为输出的观察数（y）。\n",
    "        dropnan：布尔值，决定是否删除具有NaN值的行。\n",
    "    返回：\n",
    "    pd.DataFrame(用于监督学习)\n",
    "    \"\"\"\n",
    "    n_vars = 1 if type(data) is list else data.shape[1]\n",
    "    df = pd.DataFrame(data)\n",
    "    cols, names = list(), list()\n",
    "    # input sequence (t-n, ... t-1)\n",
    "    for i in range(n_in, 0, -1):\n",
    "        cols.append(df.shift(i))\n",
    "        names += [('var%d(t-%d)' % (j + 1, i)) for j in range(n_vars)]\n",
    "    # forecast sequence (t, t+1, ... t+n)\n",
    "    for i in range(0, n_out):\n",
    "        cols.append(df.shift(-i))\n",
    "        if i == 0:\n",
    "            names += [('var%d(t)' % (j + 1)) for j in range(n_vars)]\n",
    "        else:\n",
    "            names += [('var%d(t+%d)' % (j + 1, i)) for j in range(n_vars)]\n",
    "    # put it all together\n",
    "    agg = pd.concat(cols, axis=1)\n",
    "    agg.columns = names\n",
    "    # drop rows with NaN values\n",
    "    if dropnan:\n",
    "        agg.dropna(inplace=True)\n",
    "    return agg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "b4599843",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 将时间序列转换为监督学习问题\n",
    "reframed = series_to_supervised(scaled, 1, 1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "885302e4",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>var1(t-1)</th>\n",
       "      <th>var2(t-1)</th>\n",
       "      <th>var3(t-1)</th>\n",
       "      <th>var4(t-1)</th>\n",
       "      <th>var1(t)</th>\n",
       "      <th>var2(t)</th>\n",
       "      <th>var3(t)</th>\n",
       "      <th>var4(t)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.279017</td>\n",
       "      <td>0.276744</td>\n",
       "      <td>0.251822</td>\n",
       "      <td>0.263432</td>\n",
       "      <td>0.253224</td>\n",
       "      <td>0.264336</td>\n",
       "      <td>0.267206</td>\n",
       "      <td>0.271966</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.253224</td>\n",
       "      <td>0.264336</td>\n",
       "      <td>0.267206</td>\n",
       "      <td>0.271966</td>\n",
       "      <td>0.262327</td>\n",
       "      <td>0.261008</td>\n",
       "      <td>0.274656</td>\n",
       "      <td>0.271334</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.262327</td>\n",
       "      <td>0.261008</td>\n",
       "      <td>0.274656</td>\n",
       "      <td>0.271334</td>\n",
       "      <td>0.260810</td>\n",
       "      <td>0.264942</td>\n",
       "      <td>0.277733</td>\n",
       "      <td>0.273072</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.260810</td>\n",
       "      <td>0.264942</td>\n",
       "      <td>0.277733</td>\n",
       "      <td>0.273072</td>\n",
       "      <td>0.260052</td>\n",
       "      <td>0.271448</td>\n",
       "      <td>0.277733</td>\n",
       "      <td>0.281922</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.260052</td>\n",
       "      <td>0.271448</td>\n",
       "      <td>0.277733</td>\n",
       "      <td>0.281922</td>\n",
       "      <td>0.268851</td>\n",
       "      <td>0.275382</td>\n",
       "      <td>0.287449</td>\n",
       "      <td>0.284766</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)   var1(t)   var2(t)   var3(t)  \\\n",
       "1   0.279017   0.276744   0.251822   0.263432  0.253224  0.264336  0.267206   \n",
       "2   0.253224   0.264336   0.267206   0.271966  0.262327  0.261008  0.274656   \n",
       "3   0.262327   0.261008   0.274656   0.271334  0.260810  0.264942  0.277733   \n",
       "4   0.260810   0.264942   0.277733   0.273072  0.260052  0.271448  0.277733   \n",
       "5   0.260052   0.271448   0.277733   0.281922  0.268851  0.275382  0.287449   \n",
       "\n",
       "    var4(t)  \n",
       "1  0.271966  \n",
       "2  0.271334  \n",
       "3  0.273072  \n",
       "4  0.281922  \n",
       "5  0.284766  "
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reframed.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "50b4dee4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 删除不想预测的特征列，这里只预测收盘价\n",
    "# 所以删除的是var1(t),var2(t),var3(t),\n",
    "reframed.drop(['var1(t)', 'var2(t)', 'var3(t)'], axis=1, inplace=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b79f0d7a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>var1(t-1)</th>\n",
       "      <th>var2(t-1)</th>\n",
       "      <th>var3(t-1)</th>\n",
       "      <th>var4(t-1)</th>\n",
       "      <th>var4(t)</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.279017</td>\n",
       "      <td>0.276744</td>\n",
       "      <td>0.251822</td>\n",
       "      <td>0.263432</td>\n",
       "      <td>0.271966</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.253224</td>\n",
       "      <td>0.264336</td>\n",
       "      <td>0.267206</td>\n",
       "      <td>0.271966</td>\n",
       "      <td>0.271334</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.262327</td>\n",
       "      <td>0.261008</td>\n",
       "      <td>0.274656</td>\n",
       "      <td>0.271334</td>\n",
       "      <td>0.273072</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.260810</td>\n",
       "      <td>0.264942</td>\n",
       "      <td>0.277733</td>\n",
       "      <td>0.273072</td>\n",
       "      <td>0.281922</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>0.260052</td>\n",
       "      <td>0.271448</td>\n",
       "      <td>0.277733</td>\n",
       "      <td>0.281922</td>\n",
       "      <td>0.284766</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   var1(t-1)  var2(t-1)  var3(t-1)  var4(t-1)   var4(t)\n",
       "1   0.279017   0.276744   0.251822   0.263432  0.271966\n",
       "2   0.253224   0.264336   0.267206   0.271966  0.271334\n",
       "3   0.262327   0.261008   0.274656   0.271334  0.273072\n",
       "4   0.260810   0.264942   0.277733   0.273072  0.281922\n",
       "5   0.260052   0.271448   0.277733   0.281922  0.284766"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reframed.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "91d4be5a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 划分训练集和测试集\n",
    "train = reframed.iloc[:int(len(reframed) * 0.85), :].values\n",
    "test = reframed.iloc[int(len(reframed) * 0.85):, :].values\n",
    "# 划分训练集和测试集的输入和输出\n",
    "train_X, train_y = train[:, :-1], train[:, -1]\n",
    "test_X, test_y = test[:, :-1], test[:, -1]\n",
    "# 转化为三维数据\n",
    "# reshape input to be 3D [samples, timesteps, features]\n",
    "train_X = train_X.reshape((train_X.shape[0], 1, train_X.shape[1]))\n",
    "test_X = test_X.reshape((test_X.shape[0], 1, test_X.shape[1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "474b0179",
   "metadata": {
    "scrolled": false
   },
   "outputs": [],
   "source": [
    "configs = json.load(open('./test_1/config.json', 'r'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "baa20f5c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Model] Model Compiled\n",
      "Time taken: 0:00:01.532377\n"
     ]
    }
   ],
   "source": [
    "model = Model()\n",
    "model.build_model(configs, train_X.shape[1], train_X.shape[2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "8eaa9e30",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Model] Training Started\n",
      "[Model] 50 epochs, 64 batch size\n",
      "Epoch 1/50\n",
      "59/59 [==============================] - 14s 48ms/step - loss: 0.0248 - val_loss: 6.5250e-04\n",
      "Epoch 2/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 0.0012 - val_loss: 5.3746e-04\n",
      "Epoch 3/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 7.5070e-04 - val_loss: 2.7200e-04\n",
      "Epoch 4/50\n",
      "59/59 [==============================] - 1s 17ms/step - loss: 6.9689e-04 - val_loss: 1.7377e-04\n",
      "Epoch 5/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.7092e-04 - val_loss: 1.7275e-04\n",
      "Epoch 6/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.6030e-04 - val_loss: 1.4878e-04\n",
      "Epoch 7/50\n",
      "59/59 [==============================] - 1s 14ms/step - loss: 6.2049e-04 - val_loss: 2.9504e-04\n",
      "Epoch 8/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.4730e-04 - val_loss: 1.5608e-04\n",
      "Epoch 9/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.8273e-04 - val_loss: 2.2276e-04\n",
      "Epoch 10/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 6.2527e-04 - val_loss: 2.1976e-04\n",
      "Epoch 11/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 6.2690e-04 - val_loss: 1.4571e-04\n",
      "Epoch 12/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.6966e-04 - val_loss: 1.4637e-04\n",
      "Epoch 13/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 6.0501e-04 - val_loss: 2.1668e-04\n",
      "Epoch 14/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.7590e-04 - val_loss: 4.9767e-04\n",
      "Epoch 15/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.9094e-04 - val_loss: 1.5517e-04\n",
      "Epoch 16/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 6.8766e-04 - val_loss: 1.4774e-04\n",
      "Epoch 17/50\n",
      "59/59 [==============================] - 1s 14ms/step - loss: 5.6922e-04 - val_loss: 1.5268e-04\n",
      "Epoch 18/50\n",
      "59/59 [==============================] - 1s 14ms/step - loss: 6.1424e-04 - val_loss: 1.4767e-04\n",
      "Epoch 19/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.4190e-04 - val_loss: 1.4424e-04\n",
      "Epoch 20/50\n",
      "59/59 [==============================] - 1s 13ms/step - loss: 6.0801e-04 - val_loss: 1.8519e-04\n",
      "Epoch 21/50\n",
      "59/59 [==============================] - 1s 14ms/step - loss: 5.3660e-04 - val_loss: 2.2204e-04\n",
      "Epoch 22/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.5723e-04 - val_loss: 1.5511e-04\n",
      "Epoch 23/50\n",
      "59/59 [==============================] - 1s 18ms/step - loss: 5.9224e-04 - val_loss: 1.8984e-04\n",
      "Epoch 24/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.0453e-04 - val_loss: 1.6672e-04\n",
      "Epoch 25/50\n",
      "59/59 [==============================] - 1s 18ms/step - loss: 5.4203e-04 - val_loss: 1.4032e-04\n",
      "Epoch 26/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 6.2278e-04 - val_loss: 1.4844e-04\n",
      "Epoch 27/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.7556e-04 - val_loss: 1.4418e-04\n",
      "Epoch 28/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.2719e-04 - val_loss: 1.6863e-04\n",
      "Epoch 29/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.6055e-04 - val_loss: 1.4399e-04\n",
      "Epoch 30/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 6.1170e-04 - val_loss: 3.5559e-04\n",
      "Epoch 31/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.3531e-04 - val_loss: 1.5030e-04\n",
      "Epoch 32/50\n",
      "59/59 [==============================] - 1s 13ms/step - loss: 5.0199e-04 - val_loss: 2.3735e-04\n",
      "Epoch 33/50\n",
      "59/59 [==============================] - 1s 14ms/step - loss: 5.6673e-04 - val_loss: 1.5053e-04\n",
      "Epoch 34/50\n",
      "59/59 [==============================] - 1s 13ms/step - loss: 5.4843e-04 - val_loss: 1.4842e-04\n",
      "Epoch 35/50\n",
      "59/59 [==============================] - 1s 14ms/step - loss: 5.3792e-04 - val_loss: 1.9215e-04\n",
      "Epoch 36/50\n",
      "59/59 [==============================] - 1s 17ms/step - loss: 5.4799e-04 - val_loss: 1.7691e-04\n",
      "Epoch 37/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.2502e-04 - val_loss: 1.7537e-04\n",
      "Epoch 38/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.3154e-04 - val_loss: 2.0355e-04\n",
      "Epoch 39/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.4197e-04 - val_loss: 1.7425e-04\n",
      "Epoch 40/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.7156e-04 - val_loss: 1.5127e-04\n",
      "Epoch 41/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.1008e-04 - val_loss: 1.7355e-04\n",
      "Epoch 42/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.0660e-04 - val_loss: 2.2998e-04\n",
      "Epoch 43/50\n",
      "59/59 [==============================] - 1s 17ms/step - loss: 5.1046e-04 - val_loss: 1.4416e-04\n",
      "Epoch 44/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 4.9464e-04 - val_loss: 1.4644e-04\n",
      "Epoch 45/50\n",
      "59/59 [==============================] - 1s 19ms/step - loss: 5.1506e-04 - val_loss: 1.9201e-04\n",
      "Epoch 46/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.4806e-04 - val_loss: 1.6659e-04\n",
      "Epoch 47/50\n",
      "59/59 [==============================] - 1s 16ms/step - loss: 5.4519e-04 - val_loss: 2.0291e-04\n",
      "Epoch 48/50\n",
      "59/59 [==============================] - 1s 17ms/step - loss: 4.9840e-04 - val_loss: 1.3640e-04\n",
      "Epoch 49/50\n",
      "59/59 [==============================] - 1s 15ms/step - loss: 5.1391e-04 - val_loss: 1.5809e-04\n",
      "Epoch 50/50\n",
      "59/59 [==============================] - ETA: 0s - loss: 5.2332e-0 - 1s 16ms/step - loss: 5.2262e-04 - val_loss: 1.7257e-04\n",
      "[Model] Training Completed. Model saved as save_models\n",
      "Time taken: 0:00:59.611600\n"
     ]
    }
   ],
   "source": [
    "# 内存中训练\n",
    "model.train(\n",
    "    train_X,\n",
    "    train_y,\n",
    "    epochs=configs['training']['epochs'],\n",
    "    batch_size=configs['training']['batch_size'],\n",
    "    validation_data=(test_X, test_y),\n",
    "    verbose=configs['training']['verbose'],\n",
    "    shuffle=configs['training']['shuffle'],\n",
    "    validation_freq=configs['training']['validation_freq'],\n",
    "    save_dir=configs['model']['save_dir']\n",
    ")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "cacd9cda",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Model] Predicting Point-by-Point...\n"
     ]
    }
   ],
   "source": [
    "y_predict = model.predict_point_by_point(test_X)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "03fbbff1",
   "metadata": {},
   "outputs": [],
   "source": [
    "test_X = test_X.reshape((test_X.shape[0], test_X.shape[2]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "bc49e110",
   "metadata": {},
   "outputs": [],
   "source": [
    "# invert scaling for forecast\n",
    "# 将预测结果按比例反归一化\n",
    "inv_y_test = np.concatenate((test_X[:, :3], y_predict), axis=1)\n",
    "inv_y_test = scaler.inverse_transform(inv_y_test)\n",
    "inv_y_predict = inv_y_test[:, -1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "afb90a9a",
   "metadata": {},
   "outputs": [],
   "source": [
    "# invert scaling for actual\n",
    "# 将真实结果按比例反归一化\n",
    "test_y = test_y.reshape((len(test_y), 1))\n",
    "inv_y_train = np.concatenate((test_X[:, :3], test_y), axis=1)\n",
    "inv_y_train = scaler.inverse_transform(inv_y_train)\n",
    "inv_y = inv_y_train[:, -1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "2987243d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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QGZmZn0fJ4QQokydWuDh4eGkp2szItPT0wkLCztn2aSkJJKTk0lOTiY0NLRuUQohhKikTgl8woQJzJ8/H4D58+czceLEBg1KCCFEzWpM4DfeeCNDhw5l//79REdHM2/ePGbNmsWKFSvo2rUrK1euZNasWU0RqxBCiLPU2Ae+YMGCKs+vWrWqwYMRQghRe61iMSshhBCVSQIXQohWSlFVVW2qh4WEhBATE1OnezMzM1vlKBaJu2lJ3E1L4m4aqampZGVlVTrfpAm8PhITE0lOTq65YAsjcTctibtpSdzNS7pQhBCilZIELoQQrVSrSeBJSUnNHUKdSNxNS+JuWhJ382o1feBCCCEqajUtcCGEEBW1igS+bNkyunfvTpcuXRp/84jzdD47Fqmqyt/+9je6dOlCfHw827Zta5aYjx8/zsiRI+nVqxdxcXG8+uqrrSJui8XCoEGD6Nu3L3FxcTz55JMAHD16lMGDB9OlSxeuv/56bDYbAFarleuvv54uXbowePBgUlNTmyXuM5xOJ/369WP8+PFA64g7JiaGPn36kJCQQGKitpl4S/85AcjLy2PKlCn06NGDnj17snHjxlYR93lTWziHw6F26tRJPXz4sGq1WtX4+Hh19+7dzR2W208//aRu3bpVjYuLc597+OGH1eeee05VVVV97rnn1L///e+qqqrqkiVL1HHjxqkul0vduHGjOmjQoGaJ+eTJk+rWrVtVVVXVgoICtWvXruru3btbfNwul0stLCxUVVVVbTabOmjQIHXjxo3qtddeqy5YsEBVVVW988471TfffFNVVVV944031DvvvFNVVVVdsGCBet111zVL3Ge89NJL6o033qheeeWVqqqqrSLujh07qpmZmRXOtfSfE1VV1VtuuUV99913VVVVVavVqubm5raKuM9Xi0/gGzZsUMeOHes+nj17tjp79uxmjKiyo0ePVkjg3bp1U0+ePKmqqpYsu3XrpqqqqiYlJamffvppleWa04QJE9Tly5e3qriLi4vVfv36qZs2bVKDg4NVu92uqmrFn5exY8eqGzZsUFVVVe12uxocHKy6XK5miff48ePqqFGj1FWrVqlXXnml6nK5WkXcVSXwlv5zkpeXp8bExFT6M2vpcddFi+9COXHiBO3bt3cfR0dHc+LEiWaMqGbn2rGoJX6X1NRUtm/fzuDBg1tF3E6nk4SEBMLCwhgzZgydO3cmICAAg8FQKbaz4zYYDPj7+5Odnd0scd9///288MIL6HTaX7ns7OxWEbeiKIwdO5YBAwa4N2Zp6T8nR48eJTQ0lNtuu41+/foxY8YMiouLW3zcddHiE3hrV9OORc2pqKiIyZMn88orr+Dn51fhWkuNW6/Xk5KSQlpaGps3b2bfvn3NHVKNvv/+e8LCwhgwYEBzh3LefvnlF7Zt28YPP/zAG2+8wbp16ypcb4k/Jw6Hg23btnH33Xezfft2vL29K707a4lx10WLT+BRUVEcP37cfZyWlkZUVFQzRlSzc+1Y1JK+i91uZ/LkyUydOpVJkyYBrSPuMwICAhg5ciQbN24kLy8Ph8NRKbaz43Y4HOTn5xMcHNzksa5fv55vv/2WmJgYbrjhBlavXs19993X4uM+EwtAWFgY11xzDZs3b27xPyfR0dFER0czePBgAKZMmcK2bdtafNx10eIT+MCBAzl48CBHjx7FZrPx2WefMWHChOYOq1rn2rFowoQJfPjhh6iqyqZNm/D393f/SteUVFVl+vTp9OzZkwceeKDVxJ2ZmUleXh4ApaWlrFixgp49ezJy5EgWLlxYZdxnvs/ChQsZNWpUs7S6nnvuOdLS0khNTeWzzz5j1KhRfPLJJy0+7uLiYgoLC92fly9fTu/evVv8z0lERATt27dn//79gLZ3Qa9evVp83HXSrD3wtbRkyRK1a9euaqdOndRnn322ucOp4IYbblAjIiJUg8GgRkVFqe+9956alZWljho1Su3SpYs6evRoNTs7W1VVbRTFX/7yF7VTp05q79691S1btjRLzD///LMKqH369FH79u2r9u3bV12yZEmLj/u3335TExIS1D59+qhxcXHq008/raqqqh4+fFgdOHCg2rlzZ3XKlCmqxWJRVVVVS0tL1SlTpqidO3dWBw4cqB4+fLhZ4j7bmjVr3KNQWnrchw8fVuPj49X4+Hi1V69e7r97Lf3nRFVVdfv27eqAAQPUPn36qBMnTlRzcnJaRdznS2ZiCiFEK9Xiu1CEEEJUTRK4EEK0UpLAhRCilZIELoQQrZQkcCGEaKUkgQshRCslCVwIIVopSeBCCNFK/T89TlLjT0zbBQAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_results(inv_y_predict, inv_y)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "deep",
   "language": "python",
   "name": "deep"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
